package com.igeek.oo;

/**
 * 继承
 *
 *  Dog作为子类，继承它的父类 Animal
 *      1.子类可以调用父类中一些，非私有的属性和方法
 *      2.重写，发生在继承当中，而且是子类重写父类的方法
 *          子类在重写时，除了可以将父类方法的访问修饰符权限扩大之外，其余的不能改变，存在的情况：
 *              父类的访问修饰符的权限是：
 *                  private 就不存在重写的情况
 *                  protected 那么子类的访问修饰符权限可以是：protected 或者是 public
 *                  public 那么子类的访问修饰符权限只能是：public
 *                  default 那么子类的访问修饰符权限可以是：public protected  default
 *          为了校验真的做的是重写，可以在子类重写的方法上面添加一个注解 @Override
 *      3.继承只能是单向的单个继承，即，一个子类只能继承一个父类，反之一个父类可以有多个子类
 */
public class Dog extends Animal{

    public Dog() {
        super(1);
        System.out.println("我是子类：Dog");
    }

    {
       //这是初始化代码块，可以在程序运行之初，帮助我们做一些初始化的操作：添加数据、给参数赋值...
        System.out.println("这里是子类Dog 的初始化代码块");

        count = 4;
    }

    static {
        /*
            这是静态的初始化代码块，可以在程序运行之初，在常量池中开辟空间进行存储
            同初始化代码块一样，能做一些初始化的操作：添加数据、给参数赋值...
            但是不同的是：初始化代码块是动态的，而静态资源只有一份，不管是创建几次对象，静态资源不会多次创建
         */
        System.out.println("这里是子类Dog 的 【静态的初始化】代码块");

        count = 3;

    }
    public String gender;

    public String category;

    public void changeAge(){
        //改变属性值
        age ++;

        /*
            在子类中，如果没有重写，那么可以直接调用父类中，非私有的方法
            一旦在子类中发生了重写，再调用的方法，就是子类自己的方法（就近原则）
         */
        eat();
    }

    /**
     * 子类重写了父类中的方法，将父类中抽象出来的通过的行为，做更具体化的实现
     */
    @Override
    public void eat(){
        //重写父类的方法，实现一下具体的操作
        System.out.println("狗爱吃骨头，爱吃狗粮");
    }

    public static void main(String[] args) {
        /*
            在继承当中：
                1.子类和父类创建对象的向后顺序： 父类 > 子类，先调用父类的构造函数 -> 再调用子类的构造函数
                2.如果存在默认的构造函数，那么在创建子类对象的时候，Java会帮我们自动的调用父类的默认构造函数 super();
                3.如果没有默认的构造函数，那么需要在子类的构造函数中，手动调用父类的构造函数，并传参 super(参数列表);
                    super & this 两个关键字：可以通过他们调用属性和方法，调用构造方法
                        super : 父类对象
                        this : 当前对象
                        调用构造方法的语法：super() 在子类中调用父类的无参构造函数，从而创建父类对象
                                         super(1,"tom") 在子类中调用父类的有参的构造函数，在创建父类对象的同时，给参数赋值
                                         this()  在当前类本身，调用自己的无参的构造函数
                                         this(1,"tom") 在当前类本身，调用自己的有参的构造函数，在创建对象的同时，给参数赋值
                4.如果存在初始化代码块，那么执行顺序：
                    父类的静态的初始化代码块 -> 子类的静态的初始化代码块 ->
                    父类的初始化代码块 -> 父类的构造方法 -> 子类的初始化代码块 -> 子类的构造方法
         */
        Dog dog = new Dog();
        dog.changeAge();
        System.out.println("更改的属性值：" + dog.age);

        System.out.println("静态资源的属性赋值："+Dog.count);
    }
}
